<?php

namespace DataCube\DataCubeAggregation\AI_Toolkit\Classification;

use DataCube\DataCubeAggregation\AI_Toolkit\Interfaces\ProbabilityEstimator;
use DataCube\DataCubeAggregation\AI_Toolkit\Interfaces\TrainerInterface;
use DataCube\DataCubeAggregation\Exception\CustomException;
use Phpml\Classification\SVC as PhpMlSVC;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Phpml\SupportVectorMachine\Kernel;

/**
 * PHP ML
 */
class SVC extends BaseClassifier implements TrainerInterface, ProbabilityEstimator
{
    public function __construct(array $options = [])
    {
        $resolver = new OptionsResolver();
        $this->configureOptions($resolver);
        $this->options = $resolver->resolve($options);
        $this->classifier = new PhpMlSVC(
            $this->options['kernel'],
            $this->options['cost'],
            $this->options['degree'],
            $this->options['gamma'],
            $this->options['coef0'],
            $this->options['tolerance'],
            $this->options['cacheSize'],
            $this->options['shrinking'],
            $this->options['probabilityEstimates'],
        );
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'kernel' => Kernel::LINEAR,
            'cost' => 1.0,
            'degree' => 3,
            'gamma' => null,
            'coef0' => 0.0,
            'tolerance' => 0.001,
            'cacheSize' => 100,
            'shrinking' => true,
            'probabilityEstimates' => false
        ]);
    }

    public function train(array $samples, array $targets): void
    {
        try {
            $this->classifier->train($samples, $targets);
        } catch (\Exception $e) {
        }
    }

    public function predict(array $samples)
    {
        try {
            return $this->classifier->predict($samples);
        } catch (\Exception $e) {
            throw new CustomException('Could not predict');
        }
    }

    public function predictProbability(array $sample)
    {
        if ($this->options['probabilityEstimates']) {
            try {
                return $this->classifier->predictProbability($sample);
            } catch (\Exception $e) {
            }
        }
        throw new \InvalidArgumentException('To predict probabilities you must build a classifier with $probabilityEstimates set to true.');
    }
}